#include "webserver.h"
#include "utils/utils.h"
#include "utils/httputils.h"
#include "postdatahandler.h"
#include "dao/trcoletadao.h"
#include "dao/trcoletaitemdao.h"
#include "databasecreator.h"

#define COLETA_URL "TRCOLETA"
#define COLETA_FILE COLETA_URL ".csv"

#define COLETAITEM_URL "TRCOLETAITEM"
#define COLETAITEM_FILE COLETAITEM_URL ".csv"

//---

#define EMBALAGEM_PRODUTO_URL "AQEmbalagemProduto"
#define EMBALAGEM_PRODUTO_FILE EMBALAGEM_PRODUTO_URL ".csv"

#define EMPRESA_URL "AQEmpresa"
#define EMPRESA_FILE EMPRESA_URL ".csv"

#define FORNECEDOR_URL "AQFornecedor"
#define FORNECEDOR_FILE FORNECEDOR_URL ".csv"

#define PROD_EMBALAGEM_URL "AQProdEmbalagem"
#define PROD_EMBALAGEM_FILE PROD_EMBALAGEM_URL ".csv"

#define PROD_EMPRESA_INFO_URL "AQProdEmpresaInfo"
#define PROD_EMPRESA_INFO_FILE PROD_EMPRESA_INFO_URL ".csv"

#define PROD_GRUPO_URL "AQProdGrupo"
#define PROD_GRUPO_FILE PROD_GRUPO_URL ".csv"

#define PRODUTO_URL "AQProduto"
#define PRODUTO_FILE PRODUTO_URL ".csv"

#define FORN_COLETA_URL "TRFORNCOLETA"
#define FORN_COLETA_FILE FORN_COLETA_URL ".csv"

#define FORN_COLETA_ITEM_URL "TRFORNCOLETAITEM"
#define FORN_COLETA_ITEM_FILE FORN_COLETA_ITEM_URL ".csv"

#define UPDATE_POS_URL "UpdatePos"

WebServer::WebServer(QObject *parent, int port) :
    QObject(parent)
{
    QFile dbFile("precolider.sqlite");
    bool createDB = !dbFile.exists();

    QHttpServer *server = new QHttpServer(this);

    db = new DB("QSQLITE",0,this);

    db->setDatabaseName("precolider.sqlite");
    //    db->setDatabaseName("/opt/firebird/pcp.fdb");
    //    db->setHostName("127.0.0.1");
    //    db->setUserName("SYSDBA");
    //    db->setPassword("firebird");
    db->connect();

    if(createDB) {
        DatabaseCreator dbCreator(db->getDB());
        dbCreator.createDatabase();
    }

    connect(server, SIGNAL(newRequest(QHttpRequest*, QHttpResponse*)),
            this, SLOT(handleRequest(QHttpRequest*, QHttpResponse*)));

    _started = server->listen(QHostAddress::Any, port);
}

bool WebServer::started() {
    return _started;
}

void WebServer::sendResponseFile(QHttpResponse *resp, QString fname) {
    QFile file(fname);

    QByteArray fileContent;

    if(file.open(QFile::ReadOnly)) {
        fileContent = file.readAll();
        file.close();
        HttpUtils::writeResponse(resp, QString::fromUtf8("text/csv"), fileContent);
    } else {
        HttpUtils::responseError(resp,"Unable to open file: "+fname);
    }

}

bool WebServer::updateFornPos(QHttpRequest *req)
{
    QString query = req->url().query();

    QString fornId = HttpUtils::extractGetParam(query,"id");
    QString fornLat = HttpUtils::extractGetParam(query,"lat");
    QString fornLon = HttpUtils::extractGetParam(query,"lon");

    qDebug(QString("Atualizar posocao -> ").append(fornId).append(": ").
           append(fornLat).append(",").append(fornLon).toUtf8());
//TODO    SALVAR POSICAO DO FORNECEDOR NO BD (MAS NAO TEMOS O FORNECEDOR NO BD.. TEMOS APENAS O .CSV)

    return true;
}

void WebServer::handleGet(QHttpRequest *req, QHttpResponse *resp)
{
    qDebug(req->path().toUtf8());
    if(req->path().endsWith(EMBALAGEM_PRODUTO_URL)) {
        sendResponseFile(resp, EMBALAGEM_PRODUTO_FILE);
    } else if(req->path().endsWith(EMPRESA_URL)) {
        sendResponseFile(resp, EMPRESA_FILE);
    } else if(req->path().endsWith(FORNECEDOR_URL)) {
        qDebug("SEND FORNECEDOR");
        sendResponseFile(resp, FORNECEDOR_FILE);
    } else if(req->path().endsWith(PROD_EMBALAGEM_URL)) {
        sendResponseFile(resp, PROD_EMBALAGEM_FILE);
    } else if(req->path().endsWith(PROD_EMPRESA_INFO_URL)) {
        sendResponseFile(resp, PROD_EMPRESA_INFO_FILE);
    } else if(req->path().endsWith(PROD_GRUPO_URL)) {
        sendResponseFile(resp, PROD_GRUPO_FILE);
    } else if(req->path().endsWith(PRODUTO_URL)) {
        sendResponseFile(resp, PRODUTO_FILE);
    } else if(req->path().endsWith(FORN_COLETA_URL)) {
        sendResponseFile(resp, FORN_COLETA_FILE);
    } else if(req->path().endsWith(FORN_COLETA_ITEM_URL)) {
        sendResponseFile(resp, FORN_COLETA_ITEM_FILE);
    } else if(req->path().endsWith(UPDATE_POS_URL)) {
        if(!updateFornPos(req)) {
            HttpUtils::writeJsonResponse(resp,"{\"error\": \"Nao foi possivel atualizar a posicao do fornecedor\"}");
        } else {
            HttpUtils::writeJsonResponse(resp,"{\"result\": \"OK\"}");
        }
    } else {
        HttpUtils::responseError(resp,"Unknow method");
    }
}

bool WebServer::importColetaItemsToBD(TRCOLETA *coleta, qulonglong originalId)
{
    TRCOLETAITEMDAO coletaItemDAO;
    TRCOLETAITEM *coletaItem = NULL;
    QFile coletaItemCSV(COLETAITEM_FILE);
    QStringList coletaItemFields;

    if(!coletaItemCSV.open(QFile::ReadOnly)) goto ERR;
    coletaItemFields = QString(coletaItemCSV.readLine().trimmed()).split(";");

    while(!coletaItemCSV.atEnd()) {
        QString coletaItemLine = coletaItemCSV.readLine().trimmed();

        if(coletaItemLine.isEmpty()) continue;

        coletaItem = coletaItemDAO.fromCSV(coletaItemLine,coletaItemFields);

        if(coletaItem->ID_Coleta()==originalId) {
            coletaItem->setID_Coleta(coleta->mId());
            coletaItem->setmId(0);
            if(!coletaItemDAO.save(coletaItem)) goto ERR;
        }

        delete coletaItem;
        coletaItem = NULL;
    }

    return true;

ERR:
    if(coletaItemCSV.isOpen()) coletaItemCSV.close();
    if(coletaItem) delete coletaItem;
    return false;
}

bool WebServer::importColetaToBD()
{
    TRCOLETADAO coletaDAO;
    TRCOLETA *coleta = NULL;
    QFile coletaCSV(COLETA_FILE);
    QStringList coletaFields;

    if(!coletaCSV.open(QFile::ReadOnly)) goto ERR;

    coletaFields = QString(coletaCSV.readLine().trimmed()).split(";");

    while(!coletaCSV.atEnd()) {
        QString coletaLine = coletaCSV.readLine().trimmed();
        if(coletaLine.isEmpty()) continue;

        coleta = coletaDAO.fromCSV(coletaLine,coletaFields);
        qulonglong originalId = coleta->mId();
        coleta->setmId(0);
        if(!coletaDAO.saveAndUpdateID(coleta)) goto ERR;

        if(!importColetaItemsToBD(coleta,originalId)) goto ERR;

        delete coleta;
        coleta = NULL;
    }

    coletaCSV.close();
    return true;

ERR:
    if(coletaCSV.isOpen()) coletaCSV.close();
    if(coleta) delete coleta;
    return false;
}

bool WebServer::importColeta() {
    db->beginTransaction();
    bool result = importColetaToBD();
    if(result) {
        db->commitTransaction();
    } else {
        db->rollbackTransaction();
    }

    return result;
}

bool WebServer::checkMD5AndSave(const QByteArray &data, QString fname)
{
    int pos = data.indexOf('\n');
    QString md5(data.left(pos));
    QString content(data.right(data.size()-pos-1));

    if(md5.compare(Utils::StringMD5(content),Qt::CaseInsensitive)==0) {
        return Utils::saveData(content.toUtf8(),fname);
    }

    return false;
}

void WebServer::handlePost(QHttpRequest *req, QHttpResponse *resp)
{
    QString result = "{\"error\": \"Unknow method\"}";

    if(req->path().endsWith(COLETA_URL)) {
        if(checkMD5AndSave(req->body(),QString(COLETA_FILE))) {
            result = "{\"result\": \"OK\"}";
        } else {
            result = "{\"error\": \"MD5 ERROR\"}";
        }
    }
    if(req->path().endsWith(COLETAITEM_URL)) {
        if(!checkMD5AndSave(req->body(),QString(COLETAITEM_FILE))) {
            result = "{\"error\": \"MD5 ERROR\"}";
        } else {
            if(!importColeta()) {
                result ="{\"error\": \"IMPORT ERROR\"}";
            } else {
                result = "{\"result\": \"OK\"}";
            }
        }
    }

    HttpUtils::writeJsonResponse(resp,result);
}

void WebServer::handleRequest(QHttpRequest *req, QHttpResponse *resp)
{
    qDebug(QString("REQUEST: ").append(req->url().toString()).toUtf8());
    req->setParent(resp);
    try {
        if(req->method() == QHttpRequest::HTTP_GET) {
            handleGet(req, resp);
        } else if(req->method() == QHttpRequest::HTTP_POST) {
            req->storeBody();
            PostDataHandler *postDataHandler = new PostDataHandler(req,resp,resp);

            connect(postDataHandler,SIGNAL(postDataEnd(QHttpRequest*,QHttpResponse*)),
                    this,SLOT(handlePost(QHttpRequest*,QHttpResponse*)));
        } else {
            HttpUtils::responseError(resp,"Unknow method");
        }
    } catch(DatabaseException e) {
        db->rollbackTransaction();
        HttpUtils::responseError(resp,"Erro ao se comunicar com o banco de dados");
    }
}
